using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using MediaPortal.Common.Utils;
using MediaPortal.Configuration;
using MediaPortal.GUI.Library;
using MediaPortal.Player;
using MediaPortal.Profile;

namespace ProcessPlugins.MPStartIt
{
    /// <summary>
    /// The setup form of this plugin
    /// </summary>
    public class SetupForm : Form
    {

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private readonly Container components;
        private Button btnOK;
        private CheckedListBox checkedListBox1;
        private GroupBox groupBox1;

        private readonly ArrayList availablePlugins = new ArrayList();
        private readonly ArrayList loadedPlugins = new ArrayList();
        private CheckedListBox checkedListBox2;
        private int _id;
        private int _parentID;

        public SetupForm()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.checkedListBox2 = new System.Windows.Forms.CheckedListBox();
            this.checkedListBox1 = new System.Windows.Forms.CheckedListBox();
            this.btnOK = new System.Windows.Forms.Button();
            this.groupBox1.SuspendLayout();
            this.SuspendLayout();
            // 
            // groupBox1
            // 
            this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.groupBox1.Controls.Add(this.checkedListBox2);
            this.groupBox1.Controls.Add(this.checkedListBox1);
            this.groupBox1.Location = new System.Drawing.Point(8, 8);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(353, 334);
            this.groupBox1.TabIndex = 3;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Select plugin to start:";
            // 
            // checkedListBox2
            // 
            this.checkedListBox2.CheckOnClick = true;
            this.checkedListBox2.ColumnWidth = 150;
            this.checkedListBox2.FormattingEnabled = true;
            this.checkedListBox2.HorizontalScrollbar = true;
            this.checkedListBox2.Location = new System.Drawing.Point(19, 240);
            this.checkedListBox2.MultiColumn = true;
            this.checkedListBox2.Name = "checkedListBox2";
            this.checkedListBox2.Size = new System.Drawing.Size(317, 79);
            this.checkedListBox2.TabIndex = 15;
            this.checkedListBox2.Visible = false;
            this.checkedListBox2.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.checkedListBox2_ItemCheck);
            this.checkedListBox2.SelectedIndexChanged += new System.EventHandler(this.checkedListBox2_SelectedIndexChanged);
            // 
            // checkedListBox1
            // 
            this.checkedListBox1.CheckOnClick = true;
            this.checkedListBox1.ColumnWidth = 150;
            this.checkedListBox1.FormattingEnabled = true;
            this.checkedListBox1.HorizontalScrollbar = true;
            this.checkedListBox1.Location = new System.Drawing.Point(19, 22);
            this.checkedListBox1.MultiColumn = true;
            this.checkedListBox1.Name = "checkedListBox1";
            this.checkedListBox1.Size = new System.Drawing.Size(317, 199);
            this.checkedListBox1.TabIndex = 14;
            this.checkedListBox1.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.checkedListBox1_ItemCheck);
            this.checkedListBox1.SelectedIndexChanged += new System.EventHandler(this.checkedListBox1_SelectedIndexChanged);
            // 
            // btnOK
            // 
            this.btnOK.Location = new System.Drawing.Point(269, 348);
            this.btnOK.Name = "btnOK";
            this.btnOK.Size = new System.Drawing.Size(75, 23);
            this.btnOK.TabIndex = 5;
            this.btnOK.Text = "&OK";
            this.btnOK.Click += new System.EventHandler(this.BtnOkClick);
            // 
            // SetupForm
            // 
            this.AcceptButton = this.btnOK;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(373, 383);
            this.Controls.Add(this.btnOK);
            this.Controls.Add(this.groupBox1);
            this.Name = "SetupForm";
            this.Text = "MPStartIt Configuration";
            this.Load += new System.EventHandler(this.SetupFormLoad);
            this.groupBox1.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion

        #region Nested type: ItemTag

        private class ItemTag
        {
            public string DllName;
            public bool IsEnabled;
            public bool IsExternalPlayer;
            public bool IsHome;
            public bool IsIncompatible;
            public bool IsPlugins;
            public bool IsProcess;
            public bool IsWindow;
            public ISetupForm SetupForm;
            public bool ShowDefaultHome;
            public string Type = string.Empty;
            public int WindowId = -1;
        }

        #endregion

        private void SetupFormLoad(object sender, EventArgs e)
        {
            LoadSettings();
            EnumeratePlugins();
            LoadPlugins();
            PopulateCheckBox1();
            PopulateCheckBox2();
        }

        private void BtnOkClick(object sender, EventArgs e)
        {
            GetSelectedPluginWindowID(); 
            SaveSettings();
            Settings.SaveCache();
            Close();
        }

        private void LoadSettings()
        {
            using (var xmlreader = new Settings("MediaPortal.xml"))
            {
                _id = xmlreader.GetValueAsInt("MPStartIt", "idToStart", 0);
                _parentID = xmlreader.GetValueAsInt("MPStartIt", "parentId", -1);
            }
        }

        private void SaveSettings()
        {
            using (var xmlwriter = new MPSettings())
            {
                xmlwriter.SetValue("MPStartIt", "idToStart", _id);
                xmlwriter.SetValue("MPStartIt", "parentId", _parentID);
            }
        }

        private void EnumeratePlugins()
        {
            EnumeratePluginDirectory(Config.GetSubFolder(Config.Dir.Plugins, "windows"));
        }

        private void EnumeratePluginDirectory(string directory)
        {
            if (!Directory.Exists(directory)) return;

            string[] files = Directory.GetFiles(directory, "*.dll");
            foreach (string file in files)
            {
                availablePlugins.Add(file);
            }
        }

        private void LoadPlugins()
        {
            foreach (string pluginFile in availablePlugins)
            {
                Assembly pluginAssembly = null;


                try
                {
                    Log.Debug("plugin: MPStartIt: loadPlugins {0}", pluginFile);
                    pluginAssembly = Assembly.LoadFrom(pluginFile);
                }
                catch (BadImageFormatException)
                {
                    Log.Warn("plugin: MPStartIt: {0} has a bad image format", pluginFile);
                }

                if (pluginAssembly != null)
                {
                    try
                    {
                        Type[] exportedTypes = pluginAssembly.GetExportedTypes();
                        var nonSetupWindows = new List<object>();

                        foreach (Type type in exportedTypes)
                        {
                            bool isPlugin = (type.GetInterface("MediaPortal.GUI.Library.ISetupForm") != null);
                            bool isGuiWindow = ((type.IsClass) && (type.IsSubclassOf(typeof(GUIWindow))));

                            // an abstract class cannot be instanciated
                            if (type.IsAbstract)
                            {
                                continue;
                            }

                            bool isIncompatible = !CompatibilityManager.IsPluginCompatible(type);
                            if (isIncompatible)
                            {
                                Log.Warn(
                                    "plugin: MPStartIt: Plugin {0} is incompatible with the current MediaPortal version! (File: {1})",
                                    type.FullName, pluginFile.Substring(pluginFile.LastIndexOf(@"\") + 1));
                            }

                            // Try to locate the interface we're interested in
                            if (isPlugin || isGuiWindow)
                            {
                                // Create instance of the current type
                                object pluginObject;
                                try
                                {
                                    pluginObject = Activator.CreateInstance(type);
                                }
                                catch (TargetInvocationException)
                                {
                                    MessageBox.Show(
                                        string.Format(
                                            "An error occured while loading the plugin {0}.\n\nIt's incompatible with the current MediaPortal version and won't be loaded.",
                                            type.FullName
                                            ), "MPStartIt", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    Log.Warn(
                                        "plugin: MPStartIt: Plugin {0} is incompatible with the current MediaPortal version! (File: {1})",
                                        type.FullName, pluginFile.Substring(pluginFile.LastIndexOf(@"\") + 1));
                                    continue;
                                }

                                if (isPlugin)
                                {
                                    var pluginForm = pluginObject as ISetupForm;
                                    var extPlayer = pluginObject as IExternalPlayer;
                                    var showPlugin = pluginObject as IShowPlugin;

                                    if (pluginForm != null)
                                    {
                                        var tag = new ItemTag();
                                        tag.SetupForm = pluginForm;
                                        tag.DllName = pluginFile.Substring(pluginFile.LastIndexOf(@"\") + 1);
                                        tag.WindowId = pluginForm.GetWindowId();
                                        if (tag.SetupForm.CanEnable() || tag.SetupForm.DefaultEnabled())
                                        {
                                            using (var xmlreader = new Settings("MediaPortal.xml"))
                                            {
                                                tag.IsEnabled =
                                                    xmlreader.GetValueAsBool("plugins", tag.SetupForm.PluginName(),
                                                                             tag.SetupForm.DefaultEnabled());
                                            }
                                        }
                                        else
                                        {
                                            tag.IsEnabled = tag.SetupForm.DefaultEnabled();
                                        }

                                        if (isGuiWindow)
                                        {
                                            var win = (GUIWindow)pluginObject;
                                            if (tag.WindowId == win.GetID)
                                            {
                                                tag.Type = win.GetType().ToString();
                                                tag.IsProcess = false;
                                                tag.IsWindow = true;
                                            }
                                        }
                                        else if (extPlayer != null)
                                        {
                                            tag.IsExternalPlayer = true;
                                        }
                                        else
                                        {
                                            tag.IsProcess = true;
                                        }

                                        if (showPlugin != null)
                                        {
                                            tag.ShowDefaultHome = showPlugin.ShowDefaultHome();
                                        }

                                        tag.IsIncompatible = isIncompatible;

                                        loadedPlugins.Add(tag);
                                    }
                                }
                                else
                                {
                                    nonSetupWindows.Add(pluginObject);
                                }
                            }
                        }
                        // Filter plugins from e.g. dialogs or other windows.
                        foreach (GUIWindow win in nonSetupWindows)
                        {
                            foreach (ItemTag tag in loadedPlugins)
                            {
                                if (tag.WindowId == win.GetID)
                                {
                                    tag.Type = win.GetType().ToString();
                                    tag.IsProcess = false;
                                    tag.IsWindow = true;
                                    Log.Debug(
                                        "plugin: MPStartIt: {0}, window plugin, does not implement \"ISetupForm\" and \"GUIWindow\" in the same class",
                                        tag.Type);
                                    break;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(
                            string.Format(
                                "An error occured while loading the plugin file {0}.\n\nIt's broken or incompatible with the current MediaPortal version and won't be loaded.",
                                pluginFile.Substring(pluginFile.LastIndexOf(@"\") + 1)), "MPStartIt",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                        Log.Warn(
                            "MPStartIt: Plugin file {0} is broken or incompatible with the current MediaPortal version and won't be loaded!",
                            pluginFile.Substring(pluginFile.LastIndexOf(@"\") + 1));
                        Log.Error("MPStartIt: Exception: {0}", ex);
                    }
                }
            }
        }

        private void PopulateCheckBox1()
        {
            foreach (ItemTag tag in loadedPlugins.Cast<ItemTag>().Where(tag => tag.IsWindow && tag.IsEnabled))
            {
                checkedListBox1.Items.Add(tag.SetupForm.PluginName(), IsPluginSelected(tag));
            }
            PopulateCheckBox2();
        }

        private void PopulateCheckBox2()
        {
            checkedListBox2.Items.Clear();
            checkedListBox2.Visible = false;

            bool is4TR = false;
            foreach (ItemTag tag in loadedPlugins)
            {
                if (tag.SetupForm.PluginName().Contains("For The Record")) 
                {
                    if (tag.WindowId == _parentID)
                    { 
                        is4TR = true;
                        break;
                    }
                }
            }

            switch (_parentID)
            {
                case 1: //TV
                    checkedListBox2.Visible = true;
                    if (is4TR) 
                    {
                        checkedListBox2.Items.Add("4TR TV Home", _id == 1 ? true : false);
                        checkedListBox2.Items.Add("4TR TV Guide", _id == 600 ? true : false);
                        checkedListBox2.Items.Add("4TR Search TV Guide", _id == 49850 ? true : false);
                        checkedListBox2.Items.Add("4TR Upcoming Programs", _id == 49848 ? true : false); 
                        checkedListBox2.Items.Add("4TR Recorded TV", _id == 603 ? true : false);
                        checkedListBox2.Items.Add("4TR Active Recordings", _id == 49849 ? true : false);
                    }
                    else
                    {
                        checkedListBox2.Items.Add("TV Home", _id == 1 ? true: false); 
                        checkedListBox2.Items.Add("TV Guide", _id == 600 ? true : false); 
                        checkedListBox2.Items.Add("TV Scheduler", _id == 601 ? true : false); 
                        checkedListBox2.Items.Add("Fullscreen TV", _id == 602 ? true : false);  
                        checkedListBox2.Items.Add("Recorded TV", _id == 603 ? true : false); 
                    }
                    if (checkedListBox2.CheckedItems.Count == 0) {checkedListBox2.SetItemChecked(0,true);}
                    break;
                case 30: //Radio
                    checkedListBox2.Visible = true;
                    if (is4TR) 
                    {
                        checkedListBox2.Items.Add("4TR Radio Home", _id == 1 ? true : false);
                        checkedListBox2.Items.Add("4TR Radio Guide", _id == 762 ? true : false);
                        checkedListBox2.Items.Add("4TR Recorded Radio", _id == 49852 ? true : false);
                        checkedListBox2.Items.Add("4TR Search Radio Guide", _id == 49851 ? true : false);
                    }
                    else
                    {
                    checkedListBox2.Items.Add("Radio Home", _id == 30 ? true : false); // 30
                    checkedListBox2.Items.Add("Radio Guide", _id == 762 ? true : false); // 762
                    checkedListBox2.Items.Add("Recorded Radio", _id == 763 ? true : false); // 763
                    }
                    if (checkedListBox2.CheckedItems.Count == 0) { checkedListBox2.SetItemChecked(0, true); }
                    break;
                default:
                    break;

            }
        }

        private void GetSelectedPluginWindowID()
        {
            if (checkedListBox2.Items.Count > 0)
            {
                _parentID = GetSelectedCheckBox1ID();
                _id = GetSelectedCheckBox2ID();
            }
            else
            {
                _parentID = -1;
                _id = GetSelectedCheckBox1ID();
            }
        }

        private Int32 GetSelectedCheckBox1ID()
        {
            var pluginName = "Home";
            var windowId = 0;

            foreach (var itemChecked in checkedListBox1.CheckedItems)
            {
                pluginName = itemChecked.ToString();
            }

            foreach (var tag in loadedPlugins.Cast<ItemTag>().Where(tag => tag.SetupForm.PluginName() == pluginName))
            {
                windowId = tag.WindowId;
            }

            return windowId;
        }

        private Int32 GetSelectedCheckBox2ID()
        {
            var pluginName = "Home";
            var windowId = -1;

            foreach (var itemChecked in checkedListBox2.CheckedItems)
            {
                pluginName = itemChecked.ToString();
                switch (pluginName)
                {
                    //MediaPortal TV Plugin windows
                    case "TV Home":
                        windowId = 1;
                        break;
                    case "TV Guide":
                        windowId = 600;
                        break;
                    case "TV Scheduler":
                        windowId = 601;
                        break;
                    case "Fullscreen TV":
                        windowId = 602;
                        break;
                    case "Recorded TV":
                        windowId = 603;
                        break;
                    case "Radio Home":
                        windowId = 30;
                        break;
                    case "Radio Guide":
                        windowId = 762;
                        break;
                    case "Recorded Radio":
                        windowId = 763;
                        break;
                    //For The Record TV Plugin windows
                    case "4TR TV Home":
                        windowId = 1;
                        break;
                    case "4TR TV Guide":
                        windowId = 600;
                        break;
                    case "4TR Search TV Guide":
                        windowId = 49850;
                        break;
                    case "4TR Upcoming Programs":
                        windowId = 49848;
                        break;
                    case "4TR Recorded TV":
                        windowId = 603;
                        break;
                    case "4TR Active Recordings":
                        windowId = 49849;
                        break;
                    case "4TR Radio Home":
                        windowId = 1;
                        break;
                    case "4TR Radio Guide":
                        windowId = 762;
                        break;
                    case "4TR Recorded Radio":
                        windowId = 49852;
                        break;
                    case "4TR Search Radio Guide":
                        windowId = 49851;
                        break;
                    default:
                        windowId = 0;
                        break;
                }
            }
            return windowId;
        }

        private bool IsPluginSelected(ItemTag tag)
        {

            if (_parentID == -1)
            {
                if (tag.WindowId == _id)
                {
                    return true;
                }
            }
            
            if (tag.WindowId == _parentID)
            {
                return true;
            }
                        
            return false;
        }

        private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (e.NewValue == CheckState.Checked)
                for (var ix = 0; ix < checkedListBox1.Items.Count; ++ix)
                    if (e.Index != ix) checkedListBox1.SetItemChecked(ix, false);
        }

        private void checkedListBox2_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (e.NewValue == CheckState.Checked)
                for (var ix = 0; ix < checkedListBox2.Items.Count; ++ix)
                    if (e.Index != ix) checkedListBox2.SetItemChecked(ix, false);
        }

        private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            _parentID = -1;
            if ((GetSelectedCheckBox1ID() == 1) || (GetSelectedCheckBox1ID() == 30))
            {
                _parentID = GetSelectedCheckBox1ID();
            }
            PopulateCheckBox2();
        }

        private void checkedListBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            GetSelectedPluginWindowID();
        }

    }
}